{% extends "base.html" %} {% from "_when.html" import when_field with context %} {% block title %}Finish up Β· {{ app_name }}{% endblock %} {% block body %}

{{ '🧺 Take it off' if b.kind == 'wear' else '🦴 Finish up' }}

{{ items|map(attribute='name')|join(' Β· ') }} Β· on for {{ span|dur }} {%- if b.locked %} Β· πŸ”’ caged{% endif %}

{#- πŸ”΄ A REFUSED SAVE COMES BACK FILLED IN (#40, web/kept.py): `kv` reads what the refused form sent β€” from this form's own action, or from the "log it as a past bout" button, which posts the same fields elsewhere. Rendered server-side, so the words are in the page whether or not JavaScript runs; data-kept tells app.js to leave this form alone. The error is the page's own flash, right above β€” this form is the top of the page. -#} {%- set past_action = '/kit/bout/' ~ b.id ~ '/as-past' -%} {%- set src = past_action if kept.on(past_action) else action -%} {%- macro kv(name, default='') -%}{{ kept.value(src, name, default) }}{%- endmacro -%}
{% if b.kind == 'play' %}

How did it end?

{% for o in outcomes %} {% endfor %}
{% if b.locked %}

You're locked, so the app already knows whether it happened in the cage β€” it doesn't have to ask, and it can't be told otherwise.

{% endif %} {% endif %} {% if survey %}

Questions

{#- πŸ”΄ THE SLIDER CARRIES NO `name` UNTIL IT IS MOVED, and that is the whole mechanism. An ALWAYS submits its current value β€” an untouched one posts the midpoint β€” so the obvious markup silently records a fabricated 5 for every question the pup never answered, on a form whose own help text promises the opposite. A field with no name is not submitted at all, so "not asked" is the default by construction rather than by a rule somewhere downstream. ⚠️ It degrades the right way too: with JS off nothing is ever named, so the scores are simply absent. The failure mode is losing an answer, never inventing one. -#} {#- πŸ”΄ An answer comes back ONLY if it was sent: a kept slider is named and shows its value; one the pup never moved was never submitted, so it is still unnamed and still "not asked" β€” keeping the form must not be what fabricates the midpoint. -#} {% for q in survey %} {%- set ans = kv('score.' ~ q.key) %}
{{ (ans ~ ' / ' ~ max) if ans else 'not asked' }}
{% endfor %}

Move a slider to answer it. Anything you leave alone is recorded as not asked, never as a zero β€” the app would rather know nothing than make something up.

{% endif %} {% if consumables %}
{% endif %} {#- `min` is the bout's start: a browser will not submit an end before it. -#} {{ when_field('⏱ finished earlier? set the time', value=kv('when'), min=started_local, extra='It started ' ~ (b.started_at|local) ~ ' β€” the end can’t be before that.') }} {#- πŸ”΄ THE WAY OUT OF "end before start" (#40): the bout was started NOW for something done hours ago. Always here (the `min` above means a browser never even sends the bad end), opened when that is exactly what was refused. formnovalidate: its own times are checked by the server, and `min` belongs to the field above, not to this. -#}
β†Ά it all happened earlier β€” log it as a past bout

Discards this open bout and writes it where it really happened, with everything above. Set when it started; the end is finished earlier above, or how long it lasted.

{% endblock %}